
#include "DDJwtToken.h"

DDJwtToken::DDJwtToken(string secretKey) : secretKey(secretKey) {}
DDJwtToken::DDJwtToken() : secretKey("ddoffice") {}

DDJwtToken::~DDJwtToken()
{
}

string DDJwtToken::generateToken(const std::string &userId)
{
    time_t expirationTime = time(0) + number::daysToSeconds(7);
    //        long expirationTime = std::stol(number::timestamp()) + number::daysToSeconds(7);
    cout << "generateToken.. 过期时间=" << expirationTime << " user=" << userId << endl;
    json payload;
    payload["user_id"] = userId;
    payload["exp"] = expirationTime;
    std::string payloadStr = payload.dump();
    // 加密payload

    unsigned char *digest = HMAC(EVP_sha256(), secretKey.c_str(), secretKey.length(),
                                 reinterpret_cast<const unsigned char *>(payloadStr.c_str()), payloadStr.length(),
                                 nullptr, nullptr);
    char mdString[SHA256_DIGEST_LENGTH * 2 + 1];
    std::stringstream ss;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(digest[i]);
    }
    std::strcpy(mdString, ss.str().c_str());

    return payloadStr + "." + mdString;
}

bool DDJwtToken::verifyTokenWithSignature(const std::string &original_token, const std::string &userId, const string &u_singature, string &msg)
{
    size_t pos = original_token.find(".");
    std::string payloadStr = original_token.substr(0, pos);
    std::string signature = original_token.substr(pos + 1);
    json payload = json::parse(payloadStr);
    if (payload["user_id"] != userId || signature != u_singature)
    {
        msg = "用户token错误";
        return false;
    }

    long currentTime = time(0);
    if (!payload.contains("exp") || !payload["exp"].is_number_integer())
    {
        return false;
    }
    auto expirationTime = payload["exp"].get<int64_t>();
    if (expirationTime < currentTime)
    {
        msg = "token 已过期";
        cout << "token 已过期 exp=" << expirationTime << " currentTime=" << currentTime << endl;
        return false;
    }
    return true;
}

bool DDJwtToken::verifyToken(const std::string &token, std::string &userId)
{
    size_t pos = token.find(".");
    //        std::string payloadStr = decryptPayload(token.substr(0, pos));
    std::string payloadStr = token.substr(0, pos);
    std::string signature = token.substr(pos + 1);
    json payload = json::parse(payloadStr);
    long currentTime = time(0);

    if (!verifySignature(payloadStr, signature, secretKey))
    {
        cout << "verifySignature false" << endl;
        return false;
    }
    if (payload.contains("exp") && payload["exp"].is_number_integer())
    {
        auto expirationTime = payload["exp"].get<int64_t>();
        if (expirationTime < currentTime)
        {
            cout << "expirationTime false exp=" << expirationTime << " currentTime=" << currentTime << endl;
            return false;
        }
    }
    else
    {
        return false;
    }

    // 提取userId
    if (payload.contains("user_id") && payload["user_id"].is_string())
    {
        userId = payload["user_id"].get<std::string>();
    }
    else
    {
        return false; // userId无效
    }
    return true;
}

bool DDJwtToken::verifySignature(const std::string &payloadStr, const std::string &signature, const std::string &secretKey)
{
    unsigned char *digest = HMAC(EVP_sha256(), secretKey.c_str(), secretKey.length(),
                                 reinterpret_cast<const unsigned char *>(payloadStr.c_str()), payloadStr.length(),
                                 nullptr, nullptr);
    char mdString[SHA256_DIGEST_LENGTH * 2 + 1];
    std::stringstream ss;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(digest[i]);
    }
    std::strcpy(mdString, ss.str().c_str());
    return signature == mdString;
}